import eUtils from '../../utils/every-utils'

export default class Base2DPainter {
    /**
     * @param canvas {BaseCanvas=}
     */
    constructor(canvas) {
        this.canvas = canvas;
        this._ctx = canvas.ctx;
        this._defaultConfig = {
            fillStyle: '#000',
            filter: 'none',
            font: '10px sans-serif',
            globalAlpha: 1,
            globalCompositeOperation: 'source-over',
            imageSmoothingEnabled: true,
            imageSmoothingQuality: 'low',
            lineCap: 'butt',
            lineDashOffset: 0,
            lineJoin: 'miter',
            lineWidth: 1,
            miterLimit: 10,
            shadowBlur: 0,
            shadowColor: 'rgba(0, 0, 0, 0)',
            shadowOffsetX: 0,
            shadowOffsetY: 0,
            strokeStyle: '#000',
            textAlign: 'start',
            textBaseline: 'alphabetic'
        };
        this._defaultStyle();
        this.saveContext();
    }

    _appliedStyle(config) {
        Object.keys(this._defaultConfig).forEach(key => {
            this[key] = config[key];
            this._ctx[key] = config[key];
        });
    }

    _defaultStyle() {
        // bind function
        for (let key in this._ctx) {
            if (eUtils.isFunction(this._ctx[key])) {
                Object.defineProperty(this, key, {
                    get: () => {
                        return (function () {
                            this._appliedStyle(this);
                            this._ctx[key].apply(this._ctx, arguments);
                        }).bind(this);
                    }
                });
            } else {
                if (this._defaultConfig.hasOwnProperty(key)) {
                    this[key] = this._defaultConfig[key];
                }
            }
        }
    }

    saveContext() {
        this._savedContext = this._savedContext || [];
        let thisSavedContext = {};
        Object.keys(this._defaultConfig).forEach(key => {
            thisSavedContext[key] = this[key];
        });
        this._savedContext.push(thisSavedContext);
    }

    /**
     * @param step {DrawnStep}
     */
    drawingFollowStep(step) {
        step.step.call(this, this, step.data);
    }

    /**
     * @param session {function}
     */
    drawInSession(session) {
        if (!eUtils.isFunction(session)) {
            return;
        }
        // save state
        this.saveContext();
        // this._ctx.save();
        this._ctx.beginPath();
        // in session
        session.call(this, this);
        // out session
        // this._ctx.restore();
        // apply last state.
        this._appliedStyle(this._savedContext.pop());
        // this._ctx.save();
        this._ctx.beginPath();
    }


    /**
     * @param point {Point2D}
     * @param width {number}
     * @param height {number}
     */
    rectByPoint(point, width, height) {
        this['rect'](point.x, point.y, width, height);
    }

    /**
     * @param rect {Rect}
     */
    rectByObject(rect) {
        this['rect'](rect.getHornPoints()[0].x, rect.getHornPoints()[0].y, rect.width, rect.height);
    }

    /**
     * @param deg   {number}
     * @param point {Point2D}
     */
    rotateAroundPoint(deg, point) {
        this._ctx.translate(point.x, point.y);
        this._ctx.rotate(deg * Math.PI / 180);
        this._ctx.translate(-point.x, -point.y);
    }
}